// Read ellipsometer values via LabJack
//use easyU3 code from labjack as basis

// use channel 0 as input for photodiode.
// use channel 4 as compensator control 

// outline
// test connectivity
// compensator out
// wait for reference pulse
// acquire data at every count pulse should be every 5 degrees - 72 readings
// compensator in
// wait for reference pulse
// acquire data at every count pulse should be every 5 degrees - 72 readings

// calculate delta and choose which set to use

// calculate optical properties.

// #define _PRINTDEBUGINFO_

#include "AutoE.h"

int millisleep(int time)
// function to allow delays of less that one second
{
	int millisecs, microsecs;
	struct timeval tv;
	
	millisecs=time;
	microsecs=millisecs*1000;
	
	tv.tv_sec=microsecs/1000000;
	tv.tv_usec=microsecs%1000000;
	
	select(0, NULL, NULL, NULL, &tv);
	return(0);
}

int WaitForRef(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for reference pulse 
{
	long Reference, error,DAC1Enable_Ref;
	int LoopCheck;
	double value;
	Reference=1;
	LoopCheck=1;
	while(Reference)
		// Reference is usually at a high value. wait for reference to go to a low state - this signifies the start 
		// of the cycle.
		// would use digital i/o, but there seems to be a problem picking up the switch (need signal conditioning?)
	{		
		// read in digital value from digital input
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable_Ref,4,31,&value,0,0,0,0,0,0))!=0) 
		{
			printf("LoopCheck=%3d\n",LoopCheck);
			return 1;
		}
		
		if (value<1.5) return 0; // have found an edge
		
		LoopCheck=0;
	}
	return (1);	
}

int dWaitForRef(HANDLE hDevice,u3CalibrationInfo caliInfo,WINDOW *wnd)
// Function to wait for digital reference pulse 
{
	long Reference, error,ConfigIO;
	int LoopCheck;
	Reference=E_FALSE;
	LoopCheck=1;
	ConfigIO=1;
	do
		// Reference is usually at a high value. wait for reference to go to a low state - this signifies the start 
		// of the cycle.
		
	{		
		
		if ((error=eDI( hDevice,ConfigIO,E_REF, &Reference))!=0) // read in digital value from digital input
		{
			// problem with LabJack
			wprintw(wnd,"Problem with reference signal");
			getchar();
			exit(EXIT_FAILURE);
		}
		if (Reference<1) return 0; // have found an edge
		
		ConfigIO=0;
	}while(Reference==E_FALSE);
	return (0);	
}


int WaitForCount(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for count pulse 
{
	long Reference, error,DAC1Enable_Count;
	int LoopCheck;
	double value;
	Reference=1;
	LoopCheck=1;
	while(Reference)
		// count is usually at a high value. wait for count to go to a low state - this signifies the start 
		// of the cycle.
		// would use digital i/o, but there seems to be a problem picking up the switch (need signal conditioning?)
	{		
		// read in digital value from digital input
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable_Count,5,31,&value,0,0,0,0,0,0))!=0) return 1;
		if (value<1.5) return 0; // have found an edge
		
	}
	return (1);	
}

int dWaitForCount(HANDLE hDevice,u3CalibrationInfo caliInfo)
// Function to wait for count pulse (use channel 17)
{
	long  error,Count,ConfigIO;
	int LoopCheck;
	Count=E_FALSE;
	LoopCheck=1;
	ConfigIO=1; // keeps track of whether the channel has been set to  in or out 
	do 
		// count is usually at a high value. wait for count to go to a low state - this signifies the start 
		// of the cycle.
		
	{		
		// read in digital value from digital input
		if ((error=eDI( hDevice,
					   ConfigIO,
					   E_COUNT,
					   &Count))!=0) 
		{
			return 1;
		}
		
		if (Count<1) return 0; // have found an edge
		
		ConfigIO=0; 
	}while(Count==E_FALSE);
	return (1);	
}

int CompensatorIn(HANDLE hDevice,u3CalibrationInfo caliInfo)
// routine to move compenstor into laser beam path
// CTL0 on ellipsometer - connect to channel 16 on U3 box

{
	long ConfigIO,error;
	ConfigIO=1;
	
	if ((error=eDO( hDevice, ConfigIO,E_COMP,1)!=0))
	{
		return 1;
	}
	ConfigIO=0;// channel is now set to  digital output
	return 0;
}

int CompensatorOut(HANDLE hDevice,u3CalibrationInfo caliInfo)
// routine to move compenstor into laser beam path
// CTL0 on ellipsometer - connect to channel 4 on U3 box

{
	long ConfigIO,error;
	ConfigIO=1;
	
	if ((error=eDO( hDevice, ConfigIO,E_COMP,0)!=0))
	{
		return 1;
	}
	ConfigIO=0;// channel is now set to  digital output
	return 0;
}

int CollectValues(WINDOW *mainwnd, HANDLE hDevice, u3CalibrationInfo caliInfo, int nValues, double* VArray)
// function to aquire nValues voltages from the ellipsometer and store them in the array VArray
{
	long LoopCheck;
	int values;
	int error;
	long DAC1Enable;
	double value;
	values=0;
	DAC1Enable=1;
	LoopCheck=1;
#ifdef _PRINTDEBUGINFO_
	printw("Collectvalues\n");
#endif
	while(values<nValues) // use  360 degrees (5 degree intervals - this is set by the ellipsometer hardware)
	{
		//		Count=1;
		
		// wait for a count pulse  
		
		if (dWaitForCount(hDevice, caliInfo))
		{
			printw("Count fail\n");
			refresh();
			getchar();
			exit(EXIT_FAILURE);
		}
		// Now get photodiode value	
		if ((error=eAIN( hDevice,&caliInfo,LoopCheck,&DAC1Enable,0,31,&value,0,0,0,0,0,0))!=0) 
		{
			wprintw(mainwnd,"Analogue read error");
			refresh();
			millisleep(2000);
			return 1;
		}
#ifdef _PRINTDEBUGINFO_
		if (values%2==0)
		{
			printw("count=%d, value=%f\n",values,value);
			refresh();
		}
#endif
		// function call has worked so set LoopCheck to zero for future calls
		LoopCheck=0;
		VArray[values]=value;
		//printf("AIN0 value = %.3f\n	", Voltage[values]);
		values++;
	}
	
	return 0;
}



int AutoE(WINDOW *mainwnd, ellipspar_t *ellipsparams)
{
    HANDLE hDevice;
    u3CalibrationInfo caliInfo;
    int localID;
    long Reference,Count, error;
	long ConfigIO,PCTL;
//    int MainLoop;
//    int LoopCheck;
    double* Voltage_Cin; // recorded values with compensator in beam
	double* Voltage_Cout;// recorded values with compensator out of beam
	
	// variables for Psi, Delta calculation

	double angle;
//	char texta[20];// user input angle
	// psi and delta values - subscripts according to whether compensator is used or not
	double psi_out,delta_out;
	double psi_in,delta_in;
	double psi,delta;
	
	//memory allocation
	Voltage_Cin=(double *)malloc(72*sizeof(double));
	if (Voltage_Cin==NULL)
	{
		wprintw(mainwnd,"Error allocating array memory\n");
		refresh();
		millisleep(2000);
		
		goto done;
	}
	Voltage_Cout=(double *)malloc(72*sizeof(double));
	if (Voltage_Cout==NULL)
	{
		wprintw(mainwnd,"Error allocating array memory\n");
		refresh();
		millisleep(2000);
		
		goto done;
	}
	
	// memory allocated OK.
	clear();
	
    //Open first found U3 over USB
    localID = -1;
    if( (hDevice = openUSBConnection(localID)) == NULL)
	{
		wprintw(mainwnd,"Error! No device found - plug the LabJack in!");
		refresh();
		
        goto done;
	}
    //Get calibration information from UE9
    if((getCalibrationInfo(hDevice, &caliInfo)) < 0)
        goto close;
	
	
	wprintw(mainwnd,"Testing operation of compensator\n");
	refresh();
	wprintw(mainwnd,"moving compensator into beam\n");
	refresh();
	// move compensator into beam
	if((error=CompensatorIn( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	millisleep(1000);	
	// move compensator out of beam
	wprintw(mainwnd,"moving compensator out of beam\n");
	refresh();
	if((error=CompensatorOut( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	millisleep(1000);
	
	/*
	
	// set pctl to high - channel 07 for PCTL
	ConfigIO=1;
	PCTL=07;
	if ((error=eDO( hDevice, ConfigIO,PCTL,1)!=0)) // logical 0 tells ellipsometer that computer is not ready to accept data - this is a hang over from the old system.
	{
		printw("Error setting PCTL flag!");
		refresh();
		
		goto close;
	}
	ConfigIO=0;// channel is now set to  digital output
	
	*/
	
	// need to wait for a reference pulse
#ifdef _TEST_ROUTINES_
	int c;
	do
	{
#endif
		dWaitForRef(hDevice, caliInfo,mainwnd);
#ifdef _TEST_ROUTINES_ 
		printw("Found reference pulse");
		refresh();
		
	}while((c = getch())!= 113);
#endif
	// To have got here then a reference pulse must have been detected
	// can begin to read in values  
	if((error=CollectValues(mainwnd, hDevice, caliInfo, 72, Voltage_Cout))!=0)
	{
		wprintw(mainwnd,"Error with voltage collection\n");
		refresh();
		millisleep(2000);
		goto close;
	}
	// move compensator into beam
	if((error=CompensatorIn( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	dWaitForRef(hDevice, caliInfo,mainwnd);
	if((error=CollectValues(mainwnd, hDevice, caliInfo, 72, Voltage_Cin))!=0)
	{
		wprintw(mainwnd,"Error with voltage collection\n");
		refresh();
		millisleep(2000);
		goto close;
	}
	// move compensator back out of beam
	if((error=CompensatorOut( hDevice, caliInfo))!=0)
	{
		wprintw(mainwnd,"Error with compensator\n");
		refresh();
		millisleep(5000);
		goto done;
	}
	// convert the voltages collected into psi and delta.
	VoltageToPsiDelta(Voltage_Cout, 72,  &psi_out, &delta_out,mainwnd);
	VoltageToPsiDelta(Voltage_Cin, 72,  &psi_in, &delta_in,mainwnd);
	// choose data set
	if ((delta_out<(45.*M_PI/180.))||(delta_out>(135.*M_PI/180.)))
	{
		delta=delta_in;
	}else
	{
		delta=delta_out;
	}
	psi=psi_out; // arbitary choice
	
	wprintw(mainwnd,"Psi=%1.3f  Delta=%1.3f\n",180.*psi/M_PI,180.*delta/M_PI);
	refresh();
	millisleep(1000);
	
	// solve for n, d
	solvepsidelta(mainwnd, ellipsparams,  delta,  psi);
	
	goto done;
	
	
	
	
	
	close:
    if(error > 0)
	{
		wprintw(mainwnd,"Received an error code of %ld\n", error);
	
		closeUSBConnection(hDevice);
		exit(EXIT_FAILURE);
	}
done:	
	millisleep(2000);
	return(EXIT_SUCCESS);
}


